package com.bryanbibat.flashcards.spring;

import java.util.HashSet;
import java.util.Set;

import org.json.JSONException;
import org.json.JSONArray;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

public class DeckValidator implements Validator {

  private DeckService deckService;
  private boolean insert;
  
  public DeckValidator() {
    
  }
  
  public DeckValidator(DeckService deckService) {
    this(deckService, false);
  }

  public DeckValidator(DeckService deckService, boolean insert) {
    this.insert = insert;
    this.deckService = deckService;
  }
  
  @Override
  public boolean supports(Class<?> clazz) {
    return Deck.class.equals(clazz);
  }

  @Override
  public void validate(Object obj, Errors e) {
    ValidationUtils.rejectIfEmpty(e, "id", "id.empty");
    ValidationUtils.rejectIfEmpty(e, "title", "title.empty");
    ValidationUtils.rejectIfEmpty(e, "jsonData", "data.empty");
    Deck deck = (Deck) obj;
    
    if (!e.hasFieldErrors("id") && insert) {
      if (deckService.getDeck(deck.getId()) != null) {
        e.rejectValue("id", "already.exists");
      } 
    }
    
    if (!e.hasFieldErrors("id") && !deck.getId().matches("[\\w]*")) {
      e.rejectValue("id", "must.be.alphanumeric");
    }
    
    if (!e.hasFieldErrors("id")) {
      validateData(deck.getJsonData(), e);
    }
    
  }

  public void validateData(String data, Errors errors) {
    
    try {
      JSONArray json = new JSONArray(data);
      if (json.length() < 10) {
        errors.rejectValue("jsonData", "too.few.cards");
        return;
      }
      
      Set<String> columnOne = new HashSet<String>();
      Set<String> columnTwo = new HashSet<String>();
      
      for (int i = 0; i < json.length(); i++) {
        try {
          JSONArray card = json.getJSONArray(i);
          if (card.length() < 2) {
            errors.rejectValue("jsonData", "card.too.small", new Object[]{i+1}, "");
            return;
          }
          if (columnOne.contains(card.getString(0)) ||
              columnTwo.contains(card.getString(1)) ) {
            errors.rejectValue("jsonData", "duplicate.value", new Object[]{i+1}, "");
            return;
          }
          columnOne.add(card.getString(0));
          columnTwo.add(card.getString(1));

        } catch (JSONException e) {
          errors.rejectValue("jsonData", "not.valid.card", new Object[]{i+1}, "");
          return;
        }
      }
      
    } catch (JSONException e) {
      errors.rejectValue("jsonData", "not.valid.json");
    }
  }

}
